package com.sui.bigdata.sml.web.controller;

import com.alibaba.fastjson.JSON;
import com.feidee.fdcommon.util.ToolUtils;
import com.sui.bigdata.sml.web.dto.*;
import com.sui.bigdata.sml.web.service.ExperimentService;
import com.sui.bigdata.sml.web.service.NodeGroupService;
import com.sui.bigdata.sml.web.service.NodeService;
import com.sui.bigdata.sml.web.util.Constants;
import com.sui.bigdata.sml.web.vo.DeleteNodeVO;
import com.sui.bigdata.sml.web.vo.ExperimentElementsVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author songhaicheng
 * @date 2019/11/7 14:56
 * @description
 * @reviewer
 */
@RestController
@CrossOrigin
@RequestMapping(value = "/web/ui/nodes")
@Slf4j
public class NodeController {

    @Autowired
    private NodeService service;
    @Autowired
    private ExperimentService experimentService;
    @Autowired
    private NodeGroupService groupService;

    @PostMapping
    ResponseEntity add(@RequestBody NodeDTO dto) {
        return new ResponseEntity<>(dto.setId(service.add(dto)), HttpStatus.CREATED);
    }

    @GetMapping("/{id}")
    ResponseEntity get(@PathVariable("id") Long id) {
        return new ResponseEntity<>(service.get(id), HttpStatus.OK);
    }

    @GetMapping
    ResponseEntity listByExperimentId(@RequestParam("experiment_id") Long experimentId) {
        ExperimentDTO experiment = experimentService.get(experimentId);
        List<NodeDTO> nodes = service.listByExperiment(experiment);
        // 将库前缀去掉
        nodes.forEach(node -> filterParameters(node, false));
        List<ConnectionDTO> connections = service.listAllConnectionsBetweenNodes(nodes);
        List<NodeGroupDTO> groups = groupService.listOngoingsByExperiment(experiment);
        ExperimentElementsVO elements = new ExperimentElementsVO()
                .setNodes(nodes)
                .setConnections(connections)
                .setGroups(groups);
        return new ResponseEntity<>(elements, HttpStatus.OK);
    }

    @DeleteMapping("/{id}")
    ResponseEntity delete(@PathVariable("id") Long id) {
        NodeDTO node = service.get(id);
        if (service.delete(id)) {
            // 成功删除节点后，删除连接该节点的线
            List<Long> connectionIds = service.listConnectionsByNode(node)
                    .parallelStream()
                    .map(ConnectionDTO::getId)
                    .collect(Collectors.toList());
            service.deleteConnections(connectionIds);
            DeleteNodeVO vo = new DeleteNodeVO();
            vo.setNodeId(id);
            vo.setConnectionIds(connectionIds);
            return new ResponseEntity<>(vo, HttpStatus.NO_CONTENT);
        } else {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }
    }

    @PutMapping("/{id}")
    ResponseEntity update(@PathVariable("id") Long id, @RequestBody NodeDTO dto) {
        dto.setId(id);
        // 不保存传过来的 input、output
        dto.setInput(null);
        dto.setOutput(null);
        filterParameters(dto, true);
        service.updateBatch(Collections.singletonList(dto));
        return new ResponseEntity<>(dto, HttpStatus.OK);
    }

    @PutMapping("/batch")
    ResponseEntity updateBatch(@RequestBody List<NodeDTO> dtos) {
        dtos.forEach(dto -> {
            dto.setInput(null);
            dto.setOutput(null);
            filterParameters(dto, true);
        });
        service.updateBatch(dtos);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    @PostMapping("/attach")
    ResponseEntity attach(@RequestBody ConnectionDTO dto) {
        return new ResponseEntity<>(dto.setId(service.addConnection(dto)), HttpStatus.CREATED);
    }

    @DeleteMapping("/detach/{id}")
    ResponseEntity detach(@PathVariable("id") Long id) {
        // 无需查数据库该连线是否存在
        service.deleteConnections(Collections.singletonList(id));
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }

    @GetMapping("/result/{id}")
    ResponseEntity result(@PathVariable("id") Long id) {
        NodeDTO node = service.get(id);
        NodeResultDTO result = service.getResultByNode(node);
        if (result == null ||
                !ToolUtils.isNotNull(result.getResult()) ||
                Constants.EMPTY_NODE_RESULT_CONTENT.equals(result.getResult())) {
            // 如果查出记录结果为空，则当成没有结果记录处理
            result = null;
        } else {
            // 拆解结果
            result.parseResult();
        }
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    @PostMapping("/run/{id}/{type}")
    ResponseEntity run(@PathVariable("id") Long id, @PathVariable("type") String type) {
        NodeDTO node = service.get(id);
        return new ResponseEntity<>(service.run(node, type), HttpStatus.OK);
    }

    /**
     * 给节点的 hive_table 参数进行库名解析
     *
     * @param node
     * @param in   是否是保存进数据库的操作，一般用于外界传不带库名的值进来时，需要加上库前缀。反之，在从数据库查出给外界时，需要去掉库前缀
     */
    private void filterParameters(NodeDTO node, boolean in) {
        if (node.getParameters() != null && !"".equals(node.getParameters())) {
            Map<String, Object> param = JSON.parseObject(node.getParameters());
            if (param.containsKey(Constants.HIVE_TABLE_PARAM) && param.get(Constants.HIVE_TABLE_PARAM) != null) {
                String hiveTable = param.get(Constants.HIVE_TABLE_PARAM).toString().trim();
                if (!"".equals(hiveTable)) {
                    // 保存时如果有 hive_table 参数，手动加上库前缀，反之
                    if (in) {
                        param.put(Constants.HIVE_TABLE_PARAM, Constants.HIVE_TABLE_PREFIX + hiveTable);
                    } else if (hiveTable.split("\\.").length > 1) {
                        param.put(Constants.HIVE_TABLE_PARAM, hiveTable.split("\\.")[1]);
                    }
                    node.setParameters(JSON.toJSONString(param));
                }
            }
        }
    }

}
